/*
一、创建与构造
1.1 新建字符串
    String::new() - 创建空字符串
    String::from(&str) - 从字符串字面量创建
    str.to_string() - 将 &str 转为 String
    str.to_owned() - 同上，获取所有权
1.2 容量相关
    String::with_capacity(capacity) - 预分配容量
    s.capacity() - 获取当前容量
    s.reserve(additional) - 增加容量
    s.shrink_to_fit() - 缩容到实际大小
二、修改操作
2.1 追加内容
    s.push(ch) - 追加单个字符
    s.push_str(&str) - 追加字符串
    s + &str - 拼接字符串（消耗s）
    format!("{} {}", s1, s2) - 格式化拼接
    s.extend(iter) - 从迭代器追加
2.2 插入与删除
    s.insert(idx, ch) - 插入字符
    s.insert_str(idx, &str) - 插入字符串
    s.remove(idx) - 移除指定位置字符
    s.pop() - 移除并返回最后一个字符
    s.clear() - 清空字符串
2.3 替换
    s.replace(from, to) - 替换所有匹配子串
    s.replacen(from, to, n) - 替换前n个匹配
    s.replace_range(range, &str) - 替换指定范围
三、访问与查询
3.1 长度与空检查
    s.len() - 字节长度
    s.is_empty() - 是否为空
    s.chars().count() - 字符数量(非字节)
3.2 索引访问
    s.as_bytes() - 获取字节切片
    s.as_str() - 获取 &str 切片
    s.chars() - 获取字符迭代器
    s.bytes() - 获取字节迭代器
3.3 查找操作
    s.contains(&str) - 是否包含子串
    s.starts_with(&str) - 是否以开头
    s.ends_with(&str) - 是否以结尾
    s.find(&str) - 返回第一个匹配的字节索引
    s.rfind(&str) - 返回最后一个匹配的字节索引
四、分割与截取
4.1 分割方法
    s.split(&str) - 按分隔符分割
    s.split_whitespace() - 按空白分割
    s.split_terminator(&str) - 类似split但忽略结尾空
    s.split_at(idx) - 在指定字节索引处分割
    s.split_off(idx) - 分割并转移后半部分所有权
4.2 截取方法
    s.get(range) - 安全获取子串(返回Option)
    s[range] - 直接索引(可能panic)
    s.trim() - 去除首尾空白
    s.trim_start()/trim_end() - 单独去除首/尾空白
五、转换与比较
5.1 大小写转换
    s.to_lowercase() - 转为小写
    s.to_uppercase() - 转为大写
5.2 比较操作
    s == other - 字符串相等比较
    s.cmp(&other) - 排序比较
    s.eq_ignore_ascii_case(&other) - 忽略大小写比较
5.3 类型转换
    s.parse::<T>() - 解析为其他类型
    s.into_bytes() - 转为字节向量(消耗String)
六、迭代方法
6.1 字符迭代
    s.chars() - Unicode字符迭代器
    s.char_indices() - 带索引的字符迭代器
6.2 行迭代
    s.lines() - 按行迭代
    s.split_terminator('\n') - 明确按换行分割

================================================
特性	&str	String
可变性	不可变	可变
存储位置	栈或静态内存	堆
所有权	借用	拥有
大小	固定	可增长
性能	更高效	稍慢（需要堆分配）

*/
fn main() {
    {
        let mut tmpstr = String::new();
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr = String::with_capacity(10);//定义时分配总空间。
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr.reserve(16);// 重新分配总长度。不一定是参数值，但会>=参数。
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr.shrink_to_fit();//缩小到实际长度
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr.push('a');//每次分配，总空间大于实际长度。
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr.push_str("-pushstr");//每次分配，总空间大于实际长度。
        println!("[{},{}]cap={},len={}", file!(), line!(), tmpstr.capacity(), tmpstr.len());
        tmpstr += "123";
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        tmpstr = format!("myf1,val={}", 12);
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        tmpstr.clear();
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr.is_empty());
    }
    {
        //2.2 插入与删除
        //     s.insert(idx, ch) - 插入字符
        //     s.insert_str(idx, &str) - 插入字符串
        //     s.remove(idx) - 移除指定位置字符
        //     s.pop() - 移除并返回最后一个字符
        //     s.clear() - 清空字符串
        // 2.3 替换
        //     s.replace(from, to) - 替换所有匹配子串
        //     s.replacen(from, to, n) - 替换前n个匹配
        //     s.replace_range(range, &str) - 替换指定范围
    
        let mut tmpstr = String::from("my string check string1");
        tmpstr.insert(2, '1');
        tmpstr.insert_str(3, " string1");
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        tmpstr.remove(2);
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        tmpstr.pop();
        println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        {
            // 替换需要返回到例外一个字符串中。_表示丢弃返回?
            let _ = tmpstr.replace("string", "str");
            println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpstr.capacity(), tmpstr.len(), tmpstr);
        }
        {
            // 替换需要返回到例外一个字符串中。_表示丢弃返回?
            let tmprsp = tmpstr.replace("string", "str");
            println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmprsp.capacity(), tmprsp.len(), tmprsp);
            let mut tmpr2 = tmprsp.replacen("str", "str1", 2);
            println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpr2.capacity(), tmpr2.len(), tmpr2);
            tmpr2.replace_range(3..12, "ruststr");
            println!("[{},{}]cap={},len={}: {}", file!(), line!(), tmpr2.capacity(), tmpr2.len(), tmpr2);
        }
    }

    {
        // 3.1 长度与空检查
        //     s.len() - 字节长度
        //     s.is_empty() - 是否为空
        //     s.chars().count() - 字符数量(非字节)
        // 3.2 索引访问
        //     s.as_bytes() - 获取字节切片
        //     s.as_str() - 获取 &str 切片
        //     s.chars() - 获取字符迭代器
        //     s.bytes() - 获取字节迭代器
        // 3.3 查找操作
        //     s.contains(&str) - 是否包含子串
        //     s.starts_with(&str) - 是否以开头
        //     s.ends_with(&str) - 是否以结尾
        //     s.find(&str) - 返回第一个匹配的字节索引
        //     s.rfind(&str) - 返回最后一个匹配的字节索引
        let tmpstr = String::from("青山依旧在，几度夕阳红");
        println!("[{},{}]len={},cnt={}: {}", file!(), line!(), tmpstr.len(), tmpstr.chars().count(), tmpstr);
        // &[u8]是切片；[u8, len]是数组，编译时固定长度。
        let bytebuf = tmpstr.as_bytes();
        println!("[{},{}]bytelen={},type={}: {:?}", file!(), line!(), bytebuf.len(), type_str(bytebuf), bytebuf);
        // &str是字符串切片
        let tmpslice = &tmpstr.as_str()[3..9];
        println!("[{},{}]bytelen={},type={}: {:?}", file!(), line!(), tmpslice.len(), type_str(tmpslice), tmpslice);
        let tmpslice1 = &tmpstr[6..9];
        println!("[{},{}]bytelen={},type={}: {:?}", file!(), line!(), tmpslice1.len(), type_str(tmpslice1), tmpslice1);
        // tmpslice1借用得到tmpstr+6位置。没有额外空间。
        println!("[{},{}]{:p},{:p}", file!(), line!(), tmpstr.as_ptr(), tmpslice1.as_ptr());
    }
    {
        let tmpstr = String::from("src/myfile.txt");
        match tmpstr.rfind("/") {
            Some(tmppst) => {
                println!("[{},{}]find:{}", file!(), line!(), tmppst);
                let tmpslc = &tmpstr[tmppst+1..tmpstr.len()];
                println!("[{},{}]sub:{}", file!(), line!(), tmpslc);
            }
            None => {
                println!("[{},{}]not find", file!(), line!());
                println!("[{},{}]sub:{}", file!(), line!(), tmpstr);
            }
        }
    }
    {
        // 4.1 分割方法
        //     s.split(&str) - 按分隔符分割
        //     s.split_whitespace() - 按空白分割
        //     s.split_terminator(&str) - 类似split但忽略结尾空
        //     s.split_at(idx) - 在指定字节索引处分割
        //     s.split_off(idx) - 分割并转移后半部分所有权

        let tmpstr = String::from("a=1;b=2;c=3");
        // let tmpstr = String::from("\ra=1\n");
        // core::str::iter::Split<&str>
        let tmpspl : Vec<&str> = tmpstr.trim().split(";").collect();
        println!("[{},{}]val={:?}", file!(), line!(), tmpspl);
        for tmp1 in tmpspl {
            let tmp2 : Vec<&str> = tmp1.trim().split("=").collect();
            if tmp2.len() < 2 {
                println!("[{},{}]", file!(), line!());
                continue;
            }
            println!("[{},{}]get ok, {}:{}", file!(), line!(), tmp2[0], tmp2[1]);
        }
        // core::str::iter::Split<&str>
        // println!("[{},{}]type={}", file!(), line!(), type_str(tmpspl));
    }
}

fn type_str<T>(_val: T) -> & 'static str {
    std::any::type_name::<T>()
}